
local function LPCameraScreenToVector( iScreenX, iScreenY, iScreenW, iScreenH, angCamRot, fFoV )
	--This code works by basically treating the camera like a frustrum of a pyramid.
	--We slice this frustrum at a distance "d" from the camera, where the slice will be a rectangle whose width equals the "4:3" width corresponding to the given screen height.
	fFoV = math.rad(fFoV)
	local d = 4 * iScreenH / ( 6 * math.tan( 0.5 * fFoV ) )	;
	
	--Forward, right, and up vectors (need these to convert from local to world coordinates
	local vForward = angCamRot:Forward();
	local vRight   = angCamRot:Right();
	local vUp      = angCamRot:Up();

	--Then convert vec to proper world coordinates and return it 
	return ( d * vForward + ( iScreenX - 0.5 * iScreenW ) * vRight + ( 0.5 * iScreenH - iScreenY ) * vUp ):GetNormal();
end

local scrw, scrh = ScrW(), ScrH()
function ScreenToVector( x, y )
	return LPCameraScreenToVector( x, y, scrw, scrh, EyeAngles(), LocalPlayer():GetFOV() )
end

local function VectorToLPCameraScreen( vDir, iScreenW, iScreenH, angCamRot, fFoV )
	--Same as we did above, we found distance the camera to a rectangular slice of the camera's frustrum, whose width equals the "4:3" width corresponding to the given screen height.
	fFoV = math.rad(fFoV)
	local d = 4 * iScreenH / ( 6 * math.tan( 0.5 * fFoV ) );
	local fdp = angCamRot:Forward():Dot( vDir );
 
	--fdp must be nonzero ( in other words, vDir must not be perpendicular to angCamRot:Forward() )
	--or we will get a divide by zero error when calculating vProj below.
	if fdp == 0 then
		return 0, 0, -1
	end
 
	--Using linear projection, project this vector onto the plane of the slice
	local vProj = ( d / fdp ) * vDir;
 
	--Dotting the projected vector onto the right and up vectors gives us screen positions relative to the center of the screen.
	--We add half-widths / half-heights to these coordinates to give us screen positions relative to the upper-left corner of the screen.
	--We have to subtract from the "up" instead of adding, since screen coordinates decrease as they go upwards.
	local x = 0.5 * iScreenW + angCamRot:Right():Dot( vProj );
	local y = 0.5 * iScreenH - angCamRot:Up():Dot( vProj );
 
	--Lastly we have to ensure these screen positions are actually on the screen.
	local iVisibility
	if fdp < 0 then			--Simple check to see if the object is in front of the camera
		iVisibility = -1;
	elseif x < 0 || x > iScreenW || y < 0 || y > iScreenH then	--We've already determined the object is in front of us, but it may be lurking just outside our field of vision.
		iVisibility = 0;
	else
		iVisibility = 1;
	end
 
	return x, y, iVisibility;
end

function VectorToScreen( vec ) 
	return VectorToLPCameraScreen( (vec - EyePos()):GetNormal(), scrw, scrh, EyeAngles(), LocalPlayer():GetFOV() )
end

function rScrScale( x )
    return x * math.ceil(ScrW()/1024)
end

function ScaledRect( x,y,w,h )
    surface.DrawRect( rScrScale(x*2),rScrScale(y*2),rScrScale(w*2),rScrScale(h*2) )
end

local CheckPointMat = CreateMaterial( "CheckPointMat", "UnlitGeneric", {
    ["$basetexture"] = "Sprites/autoaim_1a",
    ["$ignorez"] = "1",
    ["$vertexcolor"] = "1",
    ["$vertexalpha"] = "1",
    ["$nolod"] = "1",
} )

function surface.DrawPoint( x, y )
    surface.SetDrawColor( 0,255,0,255 )
    surface.DrawRect( x-2,y-2,4,4 )
end

local gradient = surface.GetTextureID( "gui/gradient" )
local gradient_down = surface.GetTextureID( "gui/gradient_down" )
local gradient_up = surface.GetTextureID( "gui/gradient_up" )
pos_about_nothing = Vector(0,0,0)

local healthbar = {
{ x=0, y=0, u=0, v=0 },
{ x=0, y=0, u=800/ScrW(), v=0 },
{ x=0, y=0, u=800/ScrW(), v=640/ScrH() },
{ x=0, y=0, u=0, v=640/ScrH() }
}

function GM:ScreenSizeChanged( ScrW, ScrH )
    healthbar[2].u = 800/ScrW
    healthbar[3].u = 800/ScrW
    healthbar[3].v = 640/ScrH
    healthbar[4].v = 640/ScrH
    
    g_WaitingPanel:Center()
    
    g_SpawnPanel:SetSize( rScrScale(300), rScrScale(50) )
    g_SpawnPanel:SetSpacing( rScrScale(5) )
    g_SpawnPanel:SetPadding( rScrScale(5) )
    g_SpawnPanel:EnableHorizontal( true )
    g_SpawnPanel:SetPos( ScrW/2 - g_SpawnPanel:GetWide()/2, ScrH-g_SpawnPanel:GetTall() )
    
    for _,panel in pairs( g_SpawnPanel:GetItems() ) do
        panel:SetSize( rScrScale(40), rScrScale(40) )
    end
    
    g_SpawnPanel:InvalidateLayout()
    g_SpawnPanel:Rebuild()
end

/*
**  OH GOD VIGNETTES MAKE MY DICK ROCK SOLID HARD OH GOD WHY DOES THE CODE HAVE TO BE SO BIG NGGGH.
*/

local vignette = surface.GetTextureID( "VGUI/zoom" )
local vignette_poly = {
{ x=0,y=0,u=0,v=0 },
{ x=0,y=0,u=1,v=0 },
{ x=0,y=0,u=1,v=1 },
{ x=0,y=0,u=0,v=1 }
}

function GM:DrawVignette()
    surface.SetTexture( vignette )
    surface.SetDrawColor( 255,255,255,150 )
	
    vignette_poly[1].x = 0
    vignette_poly[2].x = ScrW()/2
    vignette_poly[3].x = ScrW()/2
    vignette_poly[4].x = 0
    
    vignette_poly[1].y = 0
    vignette_poly[2].y = 0
    vignette_poly[3].y = ScrH()/2
    vignette_poly[4].y = ScrH()/2
    
    vignette_poly[1].u = 1
    vignette_poly[2].u = 0
    vignette_poly[3].u = 0
    vignette_poly[4].u = 1
    
    vignette_poly[1].v = 0
    vignette_poly[2].v = 0
    vignette_poly[3].v = 1
    vignette_poly[4].v = 1
    
    surface.DrawPoly( vignette_poly )
    
    vignette_poly[1].x = ScrW()/2
    vignette_poly[2].x = ScrW()
    vignette_poly[3].x = ScrW()
    vignette_poly[4].x = ScrW()/2
    
    vignette_poly[1].y = ScrH()/2
    vignette_poly[2].y = ScrH()/2
    vignette_poly[3].y = ScrH()
    vignette_poly[4].y = ScrH()
    
    vignette_poly[1].u = 0
    vignette_poly[2].u = 1
    vignette_poly[3].u = 1
    vignette_poly[4].u = 0
    
    vignette_poly[1].v = 1
    vignette_poly[2].v = 1
    vignette_poly[3].v = 0
    vignette_poly[4].v = 0
    
    surface.DrawPoly( vignette_poly )
    
    vignette_poly[1].x = 0
    vignette_poly[2].x = ScrW()/2
    vignette_poly[3].x = ScrW()/2
    vignette_poly[4].x = 0
    
    vignette_poly[1].y = ScrH()/2
    vignette_poly[2].y = ScrH()/2
    vignette_poly[3].y = ScrH()
    vignette_poly[4].y = ScrH()
    
    vignette_poly[1].u = 1
    vignette_poly[2].u = 0
    vignette_poly[3].u = 0
    vignette_poly[4].u = 1
    
    vignette_poly[1].v = 1
    vignette_poly[2].v = 1
    vignette_poly[3].v = 0
    vignette_poly[4].v = 0
    
    surface.DrawPoly( vignette_poly )
    
    vignette_poly[1].x = ScrW()/2
    vignette_poly[2].x = ScrW()
    vignette_poly[3].x = ScrW()
    vignette_poly[4].x = ScrW()/2
    
    vignette_poly[1].y = 0
    vignette_poly[2].y = 0
    vignette_poly[3].y = ScrH()/2
    vignette_poly[4].y = ScrH()/2
    
    vignette_poly[1].u = 0
    vignette_poly[2].u = 1
    vignette_poly[3].u = 1
    vignette_poly[4].u = 0
    
    vignette_poly[1].v = 0
    vignette_poly[2].v = 0
    vignette_poly[3].v = 1
    vignette_poly[4].v = 1
    
    surface.DrawPoly( vignette_poly )
end

function GM:HUDPaint()

    GAMEMODE:DrawVignette()
    
    local m_x, m_y = gui.MousePos()
    scrw, scrh = ScrW(), ScrH()
    
	if not GAMEMODE:OverSpawnMenu() then
		
		if LocalPlayer():GetWeapon() then
			LocalPlayer():GetWeapon():DrawHUD()
		end

	end
	
    local health = LocalPlayer():Health()
    local ratio = health/100
    healthbar[1].x = rScrScale(0 + 31.5)
    healthbar[2].x = rScrScale(600 + 31.5)
    healthbar[3].x = rScrScale(600 - 40 + 31.5)
    healthbar[4].x = rScrScale(-40 + 31.5)

    healthbar[1].y = rScrScale(0 + 65)
    healthbar[2].y = rScrScale(0 + 65)
    healthbar[3].y = rScrScale(300 + 65)
    healthbar[4].y = rScrScale(300 + 65)
    
    framebuffer.Start()
        draw.RoundedBox( 16, 0,0,211,73,color_black )
        draw.RoundedBox( 6, 3,7,205,58,color_white )
        draw.RoundedBox( 6, 5,8,203,56,Color( 170,170,170,255 ) )
        draw.RoundedBox( 6, 5,10,201,52,color_black )
    framebuffer.End()
    
    surface.SetMaterial( framebuffer.Get() )
    surface.SetDrawColor( 255,255, 255,255 )
    surface.DrawPoly( healthbar )
    
    framebuffer.Start()
        surface.SetTexture( gradient )
        surface.SetDrawColor( 140,140,140,255 )
        surface.DrawRect( 0,0,190*ratio,40 )
        surface.SetDrawColor( 216,216,216,255 )
        surface.SetTexture( gradient )
        surface.DrawRect( 0,0,90,40 )
        surface.DrawTexturedRect( 75,0,90,40 )
        surface.SetDrawColor( 255,255,255,20 )
        surface.DrawRect( 0,20,190*ratio,20 )
    framebuffer.End()
    
    local health = 100
    healthbar[1].x = rScrScale(0 + 37)
    healthbar[2].x = rScrScale(605*ratio + 37)
    healthbar[3].x = rScrScale(605*ratio - 40 + 37)
    healthbar[4].x = rScrScale(-40 + 37)

    healthbar[1].y = rScrScale(0 + 73)
    healthbar[2].y = rScrScale(0 + 73)
    healthbar[3].y = rScrScale(289 + 73)
    healthbar[4].y = rScrScale(289 + 73)
    
    surface.SetMaterial( framebuffer.Get() )
    surface.SetDrawColor( 147,228,35,255 )
    surface.SetDrawColor( 255,115,10,255 )
    surface.DrawPoly( healthbar )
    /*
    framebuffer.Start()
        GAMEMODE.LastCash = math.Approach( GAMEMODE.LastCash, LocalPlayer():GetCash(), 1 )
        draw.SimpleTextOutlined( "$"..GAMEMODE.LastCash, "HUDNumber", 10, 10, color_white, TEXT_ALIGN_LEFT, TEXT_ALIGN_TOP, 2, color_black )
        local w,h = surface.GetTextSize( "$"..GAMEMODE.LastCash )
        surface.SetTexture( gradient_up )
        surface.SetDrawColor( 90,90,90,100 )
        surface.DrawTexturedRect( 10,30,w,14 )
    framebuffer.End()
    
    local health = 100
    healthbar[1].x = rScrScale(0 + 23)
    healthbar[2].x = rScrScale(900 + 23)
    healthbar[3].x = rScrScale(900 - 140 + 23)
    healthbar[4].x = rScrScale(-140 + 23)

    healthbar[1].y = rScrScale(0 + 10)
    healthbar[2].y = rScrScale(0 + 10)
    healthbar[3].y = rScrScale(700 + 10)
    healthbar[4].y = rScrScale(700 + 10)
    
    surface.SetMaterial( framebuffer.Get() )
    surface.SetDrawColor( 255,255,255,255 )
    surface.DrawPoly( healthbar )
    */
    framebuffer.Start()
        GAMEMODE.LastCash = math.Approach( GAMEMODE.LastCash, LocalPlayer():GetCash(), 1 )
        draw.SimpleTextOutlined( "/4", "TimeFontSmall", 130, 15, color_white, TEXT_ALIGN_RIGHT, TEXT_ALIGN_TOP, 2, color_black )
        draw.SimpleTextOutlined( LocalPlayer():GetLap(), "TimeFont", 100, 15, color_white, TEXT_ALIGN_RIGHT, TEXT_ALIGN_TOP, 2, color_black )
    framebuffer.End()
    
    local health = 100
    healthbar[1].x = ScrW()-rScrScale(180)+rScrScale(0 + 23)
    healthbar[2].x = ScrW()-rScrScale(180)+rScrScale(900 + 23)
    healthbar[3].x = ScrW()-rScrScale(180)+rScrScale(900 - 140 + 23)
    healthbar[4].x = ScrW()-rScrScale(180)+rScrScale(-140 + 23)

    healthbar[1].y = rScrScale(0)
    healthbar[2].y = rScrScale(0)
    healthbar[3].y = rScrScale(700)
    healthbar[4].y = rScrScale(700)
    
    surface.SetMaterial( framebuffer.Get() )
    surface.SetDrawColor( 255,255,255,255 )
    surface.DrawPoly( healthbar )
    
	GAMEMODE:DrawMana()
	
	local vec, ang = WorldToLocal( pos_about_nothing, Angle(0,0,0), LocalPlayer():GetPos(), EyeAngles() )
    local dir = vec:Angle().y-90
    local nothing = pos_about_nothing:ToScreen()
    local pointx, pointy = ScrW()/2-math.cos( math.rad(dir) )*rScrScale(300),ScrH()/2+math.sin( math.rad(dir) )*rScrScale(180)+rScrScale(15)
	
	if dir > -30 and dir < 210 then
		surface.DrawPoint(pointx, pointy)
	else
		MsgN( dir )
		pointx, pointy = math.Clamp(nothing.x,rScrScale(55),ScrW()-rScrScale(55)),math.Clamp(nothing.y,0,ScrH())
        surface.DrawPoint(pointx, pointy)
    end
	
    surface.SetMaterial( CheckPointMat )
    surface.SetDrawColor( 255,255,255,255 )
    surface.DrawTexturedRect( pointx-8, pointy-8,16,16 )
	draw.SimpleTextOutlined( pos_about_checkpoint-1, "TimeFontSmall", pointx, pointy, color_white, TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, 2, color_black )
	
	render.SetViewPort(0,0,scrw,scrh)
    
end

local mana_draw = 0
function GM:DrawMana()
	mana_draw = math.Approach( mana_draw, LocalPlayer():GetMana(), FrameTime() * 200 )
	local health = mana_draw
	local ratio = health/100
	healthbar[1].x = ScrW()-rScrScale(180)+rScrScale(-40 + 31.5)
	healthbar[2].x = ScrW()-rScrScale(180)+rScrScale(600 - 40 + 31.5)
	healthbar[3].x = ScrW()-rScrScale(180)+rScrScale(600 + 31.5)
	healthbar[4].x = ScrW()-rScrScale(180)+rScrScale(0 + 31.5)

	healthbar[1].y = rScrScale(0 + 65)
	healthbar[2].y = rScrScale(0 + 65)
	healthbar[3].y = rScrScale(300 + 65)
	healthbar[4].y = rScrScale(300 + 65)

	framebuffer.Start()
		draw.RoundedBox( 16, 0,0,211,73,color_black )
		draw.RoundedBox( 6, 3,7,205,58,color_white )
		draw.RoundedBox( 6, 5,8,203,56,Color( 170,170,170,255 ) )
		draw.RoundedBox( 6, 5,10,201,52,color_black )
	framebuffer.End()
    
    surface.SetMaterial( framebuffer.Get() )
    surface.SetDrawColor( 255,255, 255,255 )
    surface.DrawPoly( healthbar )
    
    framebuffer.Start()
        surface.SetTexture( gradient )
        surface.SetDrawColor( 140,140,140,255 )
        surface.DrawRect( 0,0,190*ratio,40 )
        surface.SetDrawColor( 216,216,216,255 )
        surface.SetTexture( gradient )
        surface.DrawRect( 0,0,90,40 )
        surface.DrawTexturedRect( 75,0,90,40 )
        surface.SetDrawColor( 255,255,255,20 )
        surface.DrawRect( 0,20,190*ratio,20 )
    framebuffer.End()
    
    local health = 100
    healthbar[1].x = ScrW()-rScrScale(180)+rScrScale(-40 + 38.5)
    healthbar[2].x = ScrW()-rScrScale(180)+rScrScale(605*ratio - 40 + 38.5)
    healthbar[3].x = ScrW()-rScrScale(180)+rScrScale(605*ratio + 38.5)
    healthbar[4].x = ScrW()-rScrScale(180)+rScrScale(0 + 38.5)

    healthbar[1].y = rScrScale(0 + 72.65)
    healthbar[2].y = rScrScale(0 + 72.65)
    healthbar[3].y = rScrScale(289 + 72.65)
    healthbar[4].y = rScrScale(289 + 72.65)
    
    surface.SetMaterial( framebuffer.Get() )
    surface.SetDrawColor( 33,150,245,255 )
    surface.DrawPoly( healthbar )
    
    local health = 100
    healthbar[1].x = ScrW()-rScrScale(180)+rScrScale(-140 + 23)
    healthbar[2].x = ScrW()-rScrScale(180)+rScrScale(900 - 140 + 23)
    healthbar[3].x = ScrW()-rScrScale(180)+rScrScale(900 + 23)
    healthbar[4].x = ScrW()-rScrScale(180)+rScrScale(0 + 23)

    healthbar[1].y = ScrW()+rScrScale(0 + 10)
    healthbar[2].y = ScrW()+rScrScale(0 + 10)
    healthbar[3].y = ScrW()+rScrScale(700 + 10)
    healthbar[4].y = ScrW()+rScrScale(700 + 10)
    
    surface.SetMaterial( framebuffer.Get() )
    surface.SetDrawColor( 255,255,255,255 )
    surface.DrawPoly( healthbar )
end

function GM:HUDShouldDraw( sName )
    if( sName == "CHudHealth" or sName == "CHudBattery" or sName == "CHudCrosshair" ) then
        return false -- Cause Valve HUD elements are too mainstream.
    end
    return true
end

function GM:HUDDrawTargetID()
    -- You may want to fill this in so you can see the names of other melons.
    -- Use melon:GetOwner() to get the player controlling a melon.
end

local tab = {}
/*
tab[ "$pp_colour_addr" ]        = 0
tab[ "$pp_colour_addg" ]        = 0
tab[ "$pp_colour_addb" ]        = 0
tab[ "$pp_colour_brightness" ]  = -0.05
tab[ "$pp_colour_contrast" ]    = 1.46
tab[ "$pp_colour_colour" ]      = 0.6
tab[ "$pp_colour_mulr" ]        = 0
tab[ "$pp_colour_mulg" ]        = 0
tab[ "$pp_colour_mulb" ]        = 0
*/

// Cross Process
tab[ "$pp_colour_addr" ]        = 1 / 255
tab[ "$pp_colour_addg" ]        = 4 / 255
tab[ "$pp_colour_addb" ]        = 10 / 255
tab[ "$pp_colour_brightness" ]  = -0.17
tab[ "$pp_colour_contrast" ]    = 1.4
tab[ "$pp_colour_colour" ]      = 0.58
tab[ "$pp_colour_mulr" ]        = 0 / 255
tab[ "$pp_colour_mulg" ]        = 2 / 255
tab[ "$pp_colour_mulb" ]        = 5 / 255

function GM:RenderScreenspaceEffects( )
    DrawColorModify( tab )
	
	if ( !render.SupportsPixelShaders_2_0() ) then return end
	DrawToyTown( 3, ScrH()*0.32 )
end


local whiteBlink = CreateMaterial( "whiteBlink", "UnlitGeneric", { [ "$basetexture" ] = "color/white" } )

function GM:PrePlayerDraw( pl )

	pl.DrawStep = ( pl.DrawStep or 0 ) + 1
	
	if pl.DrawStep != 1 then return true end
	if pl.DRAWING then return end
    local isBlinking = math.sin( CurTime() * 70 ) >= 0

    --for _,pl in pairs( player.GetAll() ) do
        if pl.Buggy then
        
			local ang = GAMEMODE:GetFakeAngles()
		
            if pl:IsBlinking() and isBlinking then
                SetMaterialOverride( whiteBlink )
            end
            
			render.SetColorModulation( 1,1,1 )
			if pl:GetWeapon() then
				local drawPos, drawAng = pl:GetWeapon():GetDrawPos()
				pl.WorldModel:SetPos( drawPos )
				pl.WorldModel:SetAngles( drawAng )
				pl.WorldModel:SetModelScale( Vector( 0.5, 0.5, 0.5 ) )
				pl:GetWeapon():DrawWorldModel( drawPos, drawAng )
				if pl.WorldModel:LookupAttachment("muzzle") > 0 then
					pl.muzzlePos = pl.WorldModel:GetAttachment( pl.WorldModel:LookupAttachment("muzzle") ).Pos
				else
					pl.muzzlePos = nil
				end
				pl.WorldModel:SetModelScale( Vector( 0.01, 0.01, 0.01 ) )
			end
			
			pl.Buggy:SetPos( pl:GetBuggyPos() )
			pl.Buggy:SetAngles( pl:GetBuggyAngle() )
			pl.Buggy:SetColor( 255,255,255,255 )
			pl.DRAWING = true
			
			pl.Buggy:SetModel( "models/buggy.mdl" )
            pl.Buggy:SetModelScale( Vector( 0.1,0.1,0.1 ) )
            pl.Buggy:DrawModel()
			pl.Buggy:SetModel( pl:GetModel() )
            pl.Buggy:SetModelScale( Vector( 0.01,0.01,0.01 ) )
			
			
			local olPos = pl:GetPos()
			pl:SetModelScale( Vector(0.1,0.1,0.1) )
			pl:SetPos( pl:GetPos() - Vector( 0,0,1 ) + ang:Forward()*4 )
			pl:SetAngles( pl.Buggy:GetAngles() )
			--pl:DrawModel()
			pl:SetPos( olPos )
			pl.DRAWING = false
            
            SetMaterialOverride(  )
            
        end
	--end
	
	return true
		
end

function GM:PostPlayerDraw( pl )
	
end

function GM:PreDrawOpaqueRenderables()
	for _,pl in pairs( player.GetAll() ) do
		pl.DrawStep = 0
	end
end

function GM:PostDrawOpaqueRenderables()

    for k,v in pairs( ents.FindByClass( "class CLuaEffect" ) ) do
        if v.Render then
            v:Render()
        end
    end
    
    local isBlinking = math.sin( CurTime() * 70 ) >= 0

    if isBlinking then
        SetMaterialOverride( whiteBlink )
        for k,v in pairs( ents.GetAll() ) do
            if v:IsPlayer() then continue end
            if v:IsBlinking() then v:DrawModel() end
        end
        SetMaterialOverride()
    end
    
    //GAMEMODE:DrawBlock( pl.Creator, trRes.HitPos + trRes.HitNormal*5, trRes.HitNormal:Angle():Up():Angle() )
end

function GM:PostDrawTranslucentRenderables()

	if framebuffer.IsRendering() then return end

    local pl = LocalPlayer()
    local mx, my = gui.MousePos()
    local trRes = util.TraceLine( { start = EyePos()/*pl:GetPos() - EyeAngles():Forward()*15 + EyeAngles():Up()*5*/, endpos = EyePos() + ScreenToVector( mx, my ) * 1024, filter = { pl, pl.Buggy } } )

	GAMEMODE:DrawBlock( pl.Creator, trRes.HitPos + trRes.HitNormal*7, trRes.HitNormal:Angle():Up():Angle() )

end
